﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Microsoft.HomeServer.Extensibility;
using Microsoft.HomeServer.SDK.Interop.v1;
using RouterControl.IO;
using RouterControl.Whs.SingletonService;
using RouterControl.WhsAddIn.Wizards.SelectRouter;

namespace RouterControl.WhsAddIn
{
	public partial class RouterControlSettingsTab2 : UserControl, ISettingsTab
	{
		internal delegate void OnSettingsCommittedDelegate(SettingsCache cache);

		public static readonly Guid SettingsTabGuid = new Guid("{E3B0A1D8-5EFF-49a4-83C3-4B86F850668B}");
		internal event OnSettingsCommittedDelegate OnSettingsCommitted;

		public enum SettingsState
		{
			Undefined,
			WindowsServiceNotRunning,
			SearchingForRouter,
			Ready,
        }

        #region settings

        internal class SettingsCache
		{
            private readonly log4net.ILog _log = Logging.LogFactory.Instance.GetLog<SettingsCache>();
            private bool _loaded;

            public string SelectedRouterDeviceUniqueName
            {
                get;
                set;
            }

			public bool AllowSchemaUpload
            {
                get;
                set;
            }

			public bool EnableTrafficGraph
            {
                get;
                set;
            }

            public ExtendedEnabled EnablePortForwardingMonitoring
            {
                get;
                set;
            }

            public bool EnableErrorReporting
            {
                get;
                set;
            }

            public bool EnableRouterHijackingDetection
            {
                get;
                set;
            }

			public void LoadFromSettings()
			{
                try
                {
                    var s = Properties.Settings.Default;

                    this.AllowSchemaUpload = s.AllowSchemaUpload;

                    // load singleton service settings
                    using (var ss = new SingletonService2Factory())
                    {
                        if (ss.IsWindowsServiceRunning() == SingletonService2Factory.ServiceStatus.Running)
                        {
                            var settings = ss.Channel.GetAllSettings();

                            this.SelectedRouterDeviceUniqueName = settings.SelectedDeviceId;
                            this.EnableTrafficGraph = settings.TrafficStatsEnabled;
                            this.EnablePortForwardingMonitoring = settings.PortForwardingsMonitoringEnabled;
                            this.EnableErrorReporting = settings.ErrorReportsSubmissionEnabled;
                            this.EnableRouterHijackingDetection = settings.RouterHijackingDetectionEnabled;
                        }
                    }
                }
                catch (Exception ex)
                {
                    _log.Fatal("Failed to load settings", ex);

                    throw;
                }
                finally
                {
                    _loaded = true;
                }
            }

			public void SaveToSettings(bool saveSettings)
			{
                // do not save if no settings have been loaded
                if (!_loaded)
                    return;

				try
				{
					var s = Properties.Settings.Default;
	
					s.AllowSchemaUpload = this.AllowSchemaUpload;
                    //s.ExpertMode = this.ExpertMode;   // expert mode is not saved!!
	
					if (saveSettings)
					{
						// save local settings
						s.Save();
	
						// save singleton service settings
                        using (var ss = new SingletonService2Factory())
                        {
                            if (ss.IsWindowsServiceRunning() == SingletonService2Factory.ServiceStatus.Running)
                            {
                                ss.Channel.SetAllSettings(new SettingsAll()
                                {
                                    SelectedDeviceId = this.SelectedRouterDeviceUniqueName,
                                    TrafficStatsEnabled = this.EnableTrafficGraph,
                                    PortForwardingsMonitoringEnabled = this.EnablePortForwardingMonitoring,
                                    ErrorReportsSubmissionEnabled = this.EnableErrorReporting,
                                    RouterHijackingDetectionEnabled = this.EnableRouterHijackingDetection
                                });
                            }
                        }
					}
				}
				catch (Exception ex)
				{
                    _log.Fatal("Failed to save settings", ex);

                    throw;
				}
			}
        }

        #endregion

        private readonly log4net.ILog _log = Logging.LogFactory.Instance.GetLog<RouterControlSettingsTab2>();
		private IConsoleServices _services;
		private WHSInfoClass _whsInfo;
        private SingletonService2Factory _singletonService = new SingletonService2Factory();
		private SettingsState _state = SettingsState.Undefined;
		private SettingsCache _settings = new SettingsCache();

		public IConsoleServices Services
		{
			get { return _services; }
		}

		internal SettingsCache Settings
		{
			get { return _settings; }
		}

		public RouterControlSettingsTab2(int width, int height, IConsoleServices consoleServices)
		{
			if (_log.IsDebugEnabled)
				_log.Debug("Initialization start");

			try
			{
				_services = consoleServices;
				_whsInfo = new WHSInfoClass();
				_whsInfo.Init(Whs.Properties.Constants.ApplicationName);
	
				this.Size = new Size(width, height);
	
				InitializeComponent();

                this.versionLabel.Text = ("v" + RouterControlVersion.VersionString);

                // add tab images
                this.imageListTabIcons.Images.Add(Properties.Resources.imgRouter16);
                this.imageListTabIcons.Images.Add(Properties.Resources.imgFeatures16);
                this.imageListTabIcons.Images.Add(Properties.Resources.imgMaintaince16);
                this.imageListTabIcons.Images.Add(Properties.Resources.imgAbout16);

				// done
				if (_log.IsDebugEnabled)
					_log.Debug("Initialization done");
			}
			catch (Exception e)
			{
				_log.Fatal("Failed to initialize", e);

				throw;
			}
		}

		public bool Commit()
		{
			if (_log.IsDebugEnabled)
				_log.Debug("Committing settings...");

			try
			{
				_settings.SaveToSettings(true);

                // handle events
				if (this.OnSettingsCommitted != null)
					OnSettingsCommitted(_settings);

                // reset router control tab
                var tt = (RouterControlConsoleTab2)_services.GetTab(RouterControlConsoleTab2.TabId);

                try
                {
                    tt.ResetState();
                }
                catch (Exception x)
                {
                    _log.Error("Failed to reset state on commit for " + tt.TabText + " (" + tt.TabIndex + ")", x);
                }
			}
			catch (Exception ex)
			{
				_log.Error("Failed to commit settings", ex);

				throw;
			}

			return true;
		}

		public bool GetHelp()
		{
			return false;
		}

		public Guid SettingsGuid
		{
			get { return SettingsTabGuid; }
		}

		public Control TabControl
		{
			get { return this; }
		}

		public Bitmap TabImage
		{
			get { return Properties.Resources.imgRouter; }
		}

		public string TabText
		{
			get { return Properties.Resources.txtRouterControlSettingsTabTitle; }
		}

		private void RouterControlSettingsTab2_Load(object sender, EventArgs e)
		{
			if (_log.IsDebugEnabled)
				_log.Debug("Loading start");

			try
			{
				//_settings.LoadFromSettings();     // settings are being loaded on each state change

				SetState(
					_singletonService.IsWindowsServiceRunning() == SingletonService2Factory.ServiceStatus.Running ?
					SettingsState.SearchingForRouter :
					SettingsState.WindowsServiceNotRunning
					);

                // select first tab as default
                this.tabControl.SelectTab(0);

				// done
				if (_log.IsDebugEnabled)
					_log.Debug("Loading done");
			}
			catch (Exception ex)
			{
				_log.Fatal("Loading failed", ex);

				throw;
			}
		}

		public void SetState(SettingsState state)
		{
			// no change?
			if (_state == state)
				return;

			// log
			if (_log.IsDebugEnabled)
				_log.Debug("Changing state start: " + _state + " to " + state);

            // reload settings
            _settings.LoadFromSettings();

			// no router stuff
			try
			{
                InitializeState(state);
	
				// finalize
				_state = state;
	
				// log
				if (_log.IsDebugEnabled)
					_log.Debug("Changing state done: " + state);
			}
			catch (Exception ex)
			{
				_log.Fatal("Failed to change state from " + _state + " to " + state, ex);

				throw;
			}
		}

        public void RefreshCurrentState()
        {
            try
            {
	            InitializeState(_state);

                _log.Info("Refreshed state: " + _state);
            }
            catch (Exception ex)
            {
                _log.Error("Failed to refresh current state: " + _state, ex);
            }
        }

        private void InitializeState(SettingsState state)
        {
            this.SuspendLayout();

            // cleanup
            CleanupFlowLayoutPanel(this.flowRouter);
            CleanupFlowLayoutPanel(this.flowFeatures);
            CleanupFlowLayoutPanel(this.flowMaintaince);
            CleanupFlowLayoutPanel(this.flowAbout);

            // change state
            switch (state)
            {
                case SettingsState.WindowsServiceNotRunning:
                    this.flowRouter.Controls.Add(new SettingsControls.RouterServiceNotRunning(this));

                    this.flowMaintaince.Controls.Add(new SettingsControls.LocalDatabase(this));

                    this.flowAbout.Controls.Add(new SettingsControls.AboutRouterControl(this));
                    break;

                case SettingsState.SearchingForRouter:
                    this.flowRouter.Controls.Add(new SettingsControls.SearchingForRouter(this));

                    this.flowMaintaince.Controls.Add(new SettingsControls.ErrorReporting(this));
                    this.flowMaintaince.Controls.Add(new SettingsControls.LocalDatabase(this));

                    this.flowAbout.Controls.Add(new SettingsControls.UpdateStatus(this));
                    this.flowAbout.Controls.Add(new SettingsControls.AboutRouterControl(this));
                    break;

                case SettingsState.Ready:
                    this.flowRouter.Controls.Add(new SettingsControls.SelectedRouter(this));
                    this.flowRouter.Controls.Add(new SettingsControls.SchemaUpload(this));

                    this.flowFeatures.Controls.Add(new SettingsControls.EnableTrafficGraph(this));
                    this.flowFeatures.Controls.Add(new SettingsControls.EnablePortForwarding(this));
                    this.flowFeatures.Controls.Add(new SettingsControls.EnableHijackingDetection(this));

                    this.flowMaintaince.Controls.Add(new SettingsControls.ErrorReporting(this));
                    this.flowMaintaince.Controls.Add(new SettingsControls.LocalDatabase(this));

                    this.flowAbout.Controls.Add(new SettingsControls.UpdateStatus(this));
                    this.flowAbout.Controls.Add(new SettingsControls.AboutRouterControl(this));
                    break;

                default:
                    _log.Warn("Unknown state: " + state);
                    break;
            }

            this.ResumeLayout();
        }

        private void CleanupFlowLayoutPanel(FlowLayoutPanel panel)
        {
            if (panel == null)
            	throw new ArgumentNullException("panel");

            foreach (SettingsControls.SettingsControlBase c in panel.Controls)
            {
                try
                {
                    c.Dispose();
                }
                catch (Exception ex)
                {
                    _log.Warn("Failed to dispose control", ex);
                }
            }

            panel.Controls.Clear();
        }

	}
}
